import { cloneDeep, debounce, get, set, has, isArray, isString } from "lodash"
import md5 from "md5"
const cache = {}
export default {
  props: {
    mode: {
      default: "edit", // 编辑模式和 edit， 展示模式 view
    },
    settings: {
      type: Object,
      default: () => {},
    },
    value: {
      default: null,
    },
    cleanWhenNoMatch: {
      // options中无与当前value匹配值时, 清空表单框(现为"过滤条件变更时"默认直接清空)
      default: true,
    },
    separator: {
      default: ",",
    },
    entityModel: {
      default: null,
    },
    isInChildren: {
      default: false,
    },
    readonly: {
      default: false,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
  },

  data() {
    return {
      options: null,
      loading: false,
      test: [],
      nullEntityModel: { id: null },
      lastFilter: null,
      isFirstChange: 0,
      dataId: null
    }
  },
  computed: {
    finalDisabled() {
      // 综合计算最终的disabled 状态
      if (this.disabled || this.readonly) {
        // 外部控制优先级最高, 且不需要做任何操作
        return true
      }
      const { type, parentCode, selectDisabled, condition } = this.settings
      let disabled = false
      if (selectDisabled) {
        if (
          type === "dict" &&
          (!parentCode ||
            parentCode === "" ||
            parentCode === "null" ||
            parentCode === "undefined")
        ) {
          // 需要判断勾选了“过滤条件为空时禁用”
          if (selectDisabled) {
            disabled = true
            this.$emit("input", null)
          }
        } else if (type === "entity") {
          // 暂时只处理了“且”的场景
          let finalCondition = get(condition, "and.items", [])
          const hasNonValue = finalCondition.some((c) => {
            let propertyValueIsNull = !c.propertyValue || c.propertyValue === ""
            // 如果绑定的是对象
            if (
              Object.prototype.toString.call(c.propertyValue) ===
              "[object Object]"
            ) {
              propertyValueIsNull = Object.keys(c.propertyValue).every(
                (key) => !c.propertyValue[key]
              )
            }
            return propertyValueIsNull
          })
          if (finalCondition.length && hasNonValue) {
            let bindValueIsNull = !this.value
            if (
              Object.prototype.toString.call(this.value) === "[object Object]"
            ) {
              bindValueIsNull = Object.keys(this.value).every(
                (key) => !this.value[key]
              )
            }
            if (selectDisabled) {
              disabled = true
              this.$emit("input", null)
            }
          }
        }
      }
      return disabled
    },

    isMultiple() {
      return (
        this.$attrs.multiple || this.$attrs.multiple === "" || this.isCheckbox
      )
    },
    isFilterable() {
      return this.$attrs.filterable || this.$attrs.filterable === ""
    },
    isClearable() {
      return this.$attrs.clearable || this.$attrs.clearable === ""
    },
    isSelect() {
      return (
        this.$options._componentTag === "PmSelect" ||
        this.$options._componentTag === "pm-select"
      )
    },
    isCheckbox() {
      return (
        this.$options._componentTag === "PmCheckboxGroup" ||
        this.$options._componentTag === "pm-checkbox-group"
      )
    },
    showContent() {
      // 如果绑定的是对象, 直接显示 label 字段
      if (this.settings) {
        console.log("this.entityModel", this.entityModel, this.value)
        let { bindType = "value", labelField } = this.settings
        if (bindType === "entity") {
          if (Array.isArray(this.entityModel)) {
            return this.entityModel
              .map((em) => this.getLabel(em, labelField, ""))
              .join(this.separator)
          }
          return this.entityModel
            ? this.getLabel(this.entityModel, labelField, "")
            : null
        }
      }
      if (Array.isArray(this.valueKey)) {
        if (this.options) {
          return this.options
            .filter((item) => this.valueKey.includes(item.value))
            .map((item) => item.label)
            .join(this.separator)
        }
      } else {
        const selectedItem =
          this.options &&
          this.options.find((item) => item.value === this.valueKey)
        return selectedItem ? selectedItem.label : ""
      }
    },
    valueIsObject() {
      return (
        !Array.isArray(this.value) &&
        Object.prototype.toString.call(this.value) === "[object Object]"
      )
    },
    valueKey: {
      get() {
        let value = cloneDeep(this.value)
        let { valueField } = this.settings
        if (this.valueIsObject) {
          return value ? value[valueField] : null
        } else {
          if (this.isMultiple) {
            if (value) {
              if (Array.isArray(value)) {
                return value
              } else {
                return value.toString().split(this.separator)
              }
            } else {
              return []
            }
          } else {
            return value
          }
        }
      },
      set(val) {
        let { bindType = "value", type } = this.settings
        if (bindType === "entity") {
          // debugger
          if (val === null || val === undefined) {
            this.$emit("input", cloneDeep(this.nullEntityModel))
            this.updateEntityModel(cloneDeep(this.nullEntityModel))
          } else {
            if (Array.isArray(val)) {
              this.$emit("input", val.join(this.separator))
            } else {
              this.$emit(
                "input",
                get(
                  this.options &&
                    this.options.find((item) => item.value === val),
                  "_data",
                  null
                )
              )
              this.updateEntityModel()
            }
          }
        } else {
          if (Array.isArray(val) && val) {
            this.$emit("input", val.join(this.separator))
          } else {
            this.$emit("input", val)
          }
          this.updateEntityModel()
        }

        if (this.$listeners.change) {
          // this.$listeners.change(val)
          this.$emit("change", val)
        }
      },
    },
    selectedItem() {
      return this.options
        ? this.options.filter((item) =>
            Array.isArray(this.valueKey)
              ? this.valueKey.includes(item.value)
              : item.value === this.valueKey
          )
        : []
    },
    dispatchProxy() {
      if (Vue.prototype.dispatchProxy) {
        return Vue.prototype.dispatchProxy(this)
      } else {
        return this.dispatch
      }
    },
    bus() {
      return this.$bus || this.$BaseBus
    },
  },
  watch: {
    settings: {
      immediate: true,
      deep: true,
      handler(val, oVal) {
        if (JSON.stringify(val) !== JSON.stringify(oVal)) {
          this.showAll = false
          this.isFirstChange++
          this.initDefault(this.$options.name === "pm-select") // pm-select 开启懒加载
        }
      },
    },
    entityModel: {
      deep: true,
      handler() {
        this.initDefault(this.$options.name === "pm-select") // pm-select 开启懒加载
      },
    },
    value(val) {
      if (!val) {
        const { type, parentCode, selectDisabled, condition } = this.settings
        if (selectDisabled && !this.disabled && !this.readonly) {
          // 在此复写禁用方法是为了区分“变更”和“清空操作”
          if (type === "entity") {
            let finalCondition = get(condition, "and.items", [])
            this.$attrs.disable = finalCondition.some((c) => {
              let valueIsNull = !c.propertyValue || c.propertyValue === ""
              // 如果绑定的是对象
              if (
                Object.prototype.toString.call(c.propertyValue) ===
                "[object Object]"
              ) {
                valueIsNull = Object.keys(c.propertyValue).every(
                  (key) => !c.propertyValue[key]
                )
              }
              return valueIsNull
            })
          } else if (type === "dict" && !parentCode) {
            this.$attrs.disabled = true
          }
        }
      } else {
        console.log("this.options", this.options.length)
        if (this.options.length === 0) {
          this.initDefault(this.$options.name === "pm-select")
        }
      }
    },
    // selectedItem:{
    //   deep:true,
    //   handler(val){
    //     if(val.length === 1){
    //       this.$emit('update:entityModel', cloneDeep(val[0]))
    //     }else{
    //       this.$emit('update:entityModel', cloneDeep(val))
    //     }
    //     // console.log('update:entityModel', val)
    //     // this.$emit('update:entityModel', val)
    //   }
    // }
  },
  created() {
    // this.initDefault(this.$options.name === 'pm-select')
  },
  methods: {
    setDefaultModelObject() {
      if (
        this.valueKey !== "" &&
        this.valueKey !== null &&
        this.valueKey !== undefined &&
        this.valueKey.length !== 0
      ) {
        if (!this.entityModel) {
          this.updateEntityModel()
        }
      }
    },

    getValue(item, valueField, defaultValue = null) {
      if (valueField) {
        return get(item, valueField, defaultValue)
      } else {
        if (item.code !== undefined) {
          return item.code || defaultValue
        }
        if (item.value !== undefined) {
          return item.value || defaultValue
        }
        if (item.id !== undefined) {
          return item.id || defaultValue
        }
      }
      return null
    },
    getLabel(item, labelField, defaultLabel = null) {
      if (labelField) {
        return get(item, labelField, defaultLabel)
      } else {
        if (item.name !== undefined) {
          return item.name || defaultLabel
        }
        if (item.label !== undefined) {
          return item.label || defaultLabel
        }
      }
      return null
    },
    updateEntityModel(obj) {
      this.$nextTick(() => {
        if (this.selectedItem.length === 1) {
          const newObj = obj || cloneDeep(this.selectedItem[0]._data)
          this.$emit("update:entityModel", newObj)
        } else if (this.selectedItem.length > 1) {
          const newObj = obj || cloneDeep(this.selectedItem.map((s) => s._data))
          this.$emit("update:entityModel", newObj)
        }
      })
    },
    setOptions(options) {
      const { labelField, valueField } = this.settings
      this._setOptions(
        options.map((op) => {
          return {
            value: this.getValue(op, valueField),
            label: this.getLabel(op, labelField),
          }
        })
      )
    },
    _setOptions(options, isLoadRemoteData = true) {
      // debugger
      this.isLoadRemoteData = isLoadRemoteData
      this.options = options
      if (this.options.length > 0) {
        this.showAll = true
      }
      const { type, selectDisabled, parentCode, condition } = this.settings
      // 1. [数据来源type为“字典”或“实体”]cleanWhenNoMatch为true且联动后的options不存在与当前选中值匹配的项时, 清空联动目标选中值
      if (
        this.cleanWhenNoMatch &&
        (type === "dict" || type === "entity") &&
        !!this.value
      ) {
        // valueKey判断当前是单选or多选
        if (
          isString(this.valueKey) &&
          !this.options.some((op) => op.value === this.valueKey)
        ) {
          this.$emit("input", null)
        } else if (isArray(this.valueKey) && this.valueKey.length) {
        }
      }
    },
    pointFilter() {
      const {
        type,
        dictTypeCode,
        entity,
        parentCode,
        cascade,
        action,
        condition,
        dataField = null,
        params,
      } = this.settings
      if (type === "entity") {
        let finalCondition = get(condition, "and.items", [])
        set(
          condition,
          "and.items",
          finalCondition.filter((c) => c.propertyValue !== "null")
        )
        return get(condition, "and.items", []).length > 0 ? condition : null
      } else if (type === "dict") {
        return { dictTypeCode, parentCode }
      }
    },
    getOptions() {
      return this.options
    },
    initDefault(lazy = false) {
      // 当绑定值为对象时初始化对象模型, 用于清空时回填
      if (
        !Array.isArray(this.value) &&
        Object.prototype.toString.call(this.value) === "[object Object]"
      ) {
        this.nullEntityModel = cloneDeep(this.value)
        Object.keys(this.nullEntityModel).forEach((key) => {
          this.nullEntityModel[key] = null
        })
      }
      const {
        type = "dict",
        options,
        labelField = "label",
        valueField = "value",
        disabledField = "disabled",
        cascaderField = "",
        labelIsFormatted = false,
        descriptionField = "description",
      } = this.settings
      // 静态数据优先
      if (options && Array.isArray(options)) {
        this._setOptions(
          options.map((item) => {
            if (typeof item === "string") {
              return {
                label: item,
                value: item,
              }
            } else {
              return {
                label:
                  labelIsFormatted && get(item, descriptionField)
                    ? `${get(
                        item,
                        descriptionField,
                        "description"
                      )}(${this.getLabel(item, labelField)})`
                    : this.getLabel(item, labelField),
                value: this.getValue(item, valueField),
                disabled: get(item, disabledField || "disabled"),
                _data: item,
              }
            }
          })
        )
        return
      }

      if (lazy && this.entityModel) {
        if ((!this.value || !this.entityModel) && this.isSelect) {
          // 开启缓存后 如果 value 为空 则 option 直接设置为 [], 阻断请求
          this._setOptions([], false)
          return
        }
        if (this.entityModel) {
          if (type !== "dict") {
            if (
              this.isFirstChange > 1 ||
              (this.lastFilter !== null &&
                JSON.stringify(this.lastFilter) !==
                  JSON.stringify(this.pointFilter()))
            ) {
              // 如果筛选条件发生变化, 则直接清空 options 和 value
              this._setOptions([])
              this.valueKey = null
              return
            }
          }
          console.log("懒加载数据...")
          if (this.isMultiple && this.entityModel.length > 0) {
            this._setOptions(
              this.entityModel.map((em) => {
                return {
                  value: this.getValue(em, valueField),
                  label: this.getLabel(em, labelField),
                  _data: em,
                }
              }),
              false
            )
            return
          } else if (
            this.entityModel[valueField] &&
            this.entityModel[labelField]
          ) {
            if (
              this.getValue(this.entityModel, valueField) ||
              this.getLabel(this.entityModel, labelField)
            ) {
              if (this.options.length === 0) {
                this._setOptions(
                  [
                    {
                      value: this.getValue(this.entityModel, valueField),
                      label: this.getLabel(this.entityModel, labelField),
                      _data: this.entityModel,
                    },
                  ],
                  false
                )
              }
              return
            }
          } else if (this.settings.type === "dict") {
            if (this.entityModel["code"] || this.entityModel["name"]) {
              if (this.options.length === 0) {
                this._setOptions(
                  [
                    {
                      value: this.entityModel["code"],
                      label: this.entityModel["name"],
                      _data: this.entityModel,
                    },
                  ],
                  false
                )
              }
              return
            }
          }
        }
      } else {
        console.log("加载全部数据...")
      }

      // 动态数据
      const dataId = md5(JSON.stringify(this.settings)).substring(0, 10)
      this.dataId = dataId
      if (cache[dataId]) {
        if (cache[dataId].loading) {
          this.bus.$on(`data:${dataId}`, (data) => {
            this._setOptions(data)
          })
        }
        return
      } else {
        cache[dataId] = {
          loading: true,
        }
      }

      const {
        dictTypeCode,
        entity,
        parentCode,
        cascade,
        action,
        condition,
        dataField = null,
        params,
      } = this.settings

      this.lastFilter = this.pointFilter() // 记录本次筛选条件
      if (this.settings.type === "dict" && dictTypeCode) {
        this.loading = true
        let response = this.dispatchProxy(
          Vue.prototype.Controllers.DictEntryController
            .queryDictEntrysByCriteria,
          {
            ...this.lastFilter,
            pageSize: 0,
            pageIndex: 0,
          }
        )
        response.then((data) => {
          if (has(data, "error")) data = data.data
          if (data) {
            this._setOptions(
              data.data.map((item) => {
                return {
                  label: item.name,
                  value: item.code,
                  _data: item,
                  disabled: get(item, disabledField || "disabled"),
                }
              })
            )
            this.bus.$emit(`data:${dataId}`, this.options)
            this.setDefaultModelObject()
            delete cache[dataId]
          }
          this.loading = false
        })
        if (response.end) {
          response.end((d) => {
            this.loading = false
          })
        }
      } else if (this.settings.type === "entity" && entity) {
        this.loading = true

        // 处理 condition
        let response = this.dispatchProxy(
          Vue.prototype.Controllers.LowcodeModelController.queryWithPage,
          {
            params: {
              entityName: entity,
              pageIndex: 0,
              pageSize: -1,
            },
            payload: {
              condition: this.lastFilter,
            },
          }
        )
        response.then((data) => {
          if (has(data, "error")) data = data.data
          if (data) {
            this._setOptions(
              data.data.map((item) => {
                return {
                  label: this.getLabel(item, labelField),
                  value: this.getValue(item, valueField),
                  disabled: get(item, disabledField || "disabled"),
                  _data: item,
                }
              })
            )

            this.bus.$emit(`data:${dataId}`, this.options)
            this.setDefaultModelObject()
            delete cache[dataId]
          }
          this.loading = false
        })
        if (response.end) {
          response.end((d) => {
            this.loading = false
          })
        }
      } else if (action) {
        this.loading = true
        this.dispatchProxy(action, params)
          .then((data) => {
            if (has(data, "error")) data = data.data
            this._setOptions(
              ([...(dataField ? data[dataField] : data)] || []).map((item) => {
                return {
                  label: get(item, labelField || "name"),
                  value: get(item, valueField || "id", ""),
                  disabled: get(item, disabledField || "disabled"),
                  _data: item,
                }
              })
            )
            this.bus.$emit(`data:${dataId}`, this.options)
            this.setDefaultModelObject()
            delete cache[dataId]
          })
          .end((d) => {
            this.loading = false
          })
      }
    },
  },
  beforeDestroy() {
    this.bus.$off(`data:${this.dataId}`)
  },
}
